#ifdef HAS_LIB_YANG
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <libyang/libyang.h>

const struct lysc_node *
find_schema_path(const struct ly_ctx *ctx, const char *schema_path)
{
    const char *end, *module_name_end;
    char *module_name = NULL;
    const struct lysc_node *node = NULL, *parent_node = NULL, *parent_node_tmp = NULL;
    const struct lys_module *module;
    size_t node_name_len;
    ly_bool found_exact_match = 0;

    /* iterate over each '/' in the path */
    while (schema_path) {
        /* example: schema_path = /listen/endpoint
         * end == NULL for endpoint, end exists for listen */
        end = strchr(schema_path + 1, '/');
        if (end) {
            node_name_len = end - schema_path - 1;
        } else {
            node_name_len = strlen(schema_path + 1);
        }

        /* ex: schema_path = /ietf-interfaces:interfaces/interface/ietf-ip:ipv4 */
        module_name_end = strchr(schema_path, ':');
        if (module_name_end && (!end || (module_name_end < end))) {
            /* only get module's name, if it is in the current scope */
            free(module_name);
            /* - 1 because module_name_end points to ':' */
            module_name = strndup(schema_path + 1, module_name_end - schema_path - 1);
            if (!module_name) {
                printf("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno));
                parent_node = NULL;
                goto cleanup;
            }
            /* move the pointer to the beginning of the node's name - 1 */
            schema_path = module_name_end;

            /* recalculate the length of the node's name, because the module prefix mustn't be compared later */
            if (module_name_end < end) {
                node_name_len = end - module_name_end - 1;
            } else if (!end) {
                node_name_len = strlen(module_name_end + 1);
            }
        }

        module = ly_ctx_get_module_implemented(ctx, module_name);
        if (!module) {
            /* unknown module name */
            parent_node = NULL;
            goto cleanup;
        }

        /* iterate over the node's siblings / module's top level containers */
        while ((node = lys_getnext(node, parent_node, module->compiled, LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHCHOICE))) {
            if (end && !strncmp(node->name, schema_path + 1, node_name_len) && (node->name[node_name_len] == '\0')) {
                /* check if the whole node's name matches and it's not just a common prefix */
                parent_node = node;
                break;
            } else if (!strncmp(node->name, schema_path + 1, node_name_len)) {
                /* do the same here, however if there is no exact match, use the last node with the same prefix */
                if (strlen(node->name) == node_name_len) {
                    parent_node = node;
                    found_exact_match = 1;
                    break;
                } else {
                    parent_node_tmp = node;
                }
            }
        }

        if (!end && !found_exact_match) {
            /* no exact match */
            parent_node = parent_node_tmp;
        }
        found_exact_match = 0;

        /* next iter */
        schema_path = strchr(schema_path + 1, '/');
    }

cleanup:
    free(module_name);
    return parent_node;
}

TEST(libyang_suite, case1) {
    
    LY_ERR ret = LY_SUCCESS;
    struct ly_ctx *ctx = NULL;
    const struct lys_module *module;

    // 初始化libyang上下文
    ret = ly_ctx_new("/home/jungle/code/libyang/tests/modules/yang", 0, &ctx);
    if (!ctx) {
        fprintf(stderr, "Failed to create context.\n");
        return ;
    }
    // 加载YANG模块
    // 假设YANG模块文件名为 "acme-system.yang"
    module = ly_ctx_load_module(ctx, "acme-system", NULL, NULL);
    if (!module) {
        fprintf(stderr, "Failed to load module.\n");
        ly_ctx_destroy(ctx);
        return ;
    }
    // 打印整个yang模型
    char *str = NULL;
    lys_print_mem(&str, module, LYS_OUT_TREE, 0);
    printf("\r\nyang module:\r\n%s\r\n", str);
    free(str);
    /* using lysc tree */
    ly_ctx_set_options(ctx, LY_CTX_SET_PRIV_PARSED);

    // 初始化输出
    char *printed;
    struct ly_out *out;
    ly_out_new_memory(&printed, 0, &out);

    // 从data path获取 lysc_node
    const struct lysc_node *node_lysc = lys_find_path(ctx, NULL, "/acme-system:system/food/tea", 0);
    lys_print_node(out, node_lysc, LYS_OUT_TREE, 0, LYS_PRINT_NO_SUBSTMT);
    int len = ly_out_printed(out);
    printf("\r\nlys_find_path:\r\n%s\r\n", printed);

    // 根据lysc_node 转 schema path
    char path[4078] = {0};
    lysc_path(node_lysc, LYSC_PATH_LOG, path, 4078);
    printf("\r\nschema path=%s\r\n", path);

    // 从schema path获取 lysc_node
    node_lysc = find_schema_path(ctx, "/acme-system:system/food/snack/late-bight/tea");
    if (node_lysc) {
        lys_print_node(out, node_lysc, LYS_OUT_TREE, 0, LYS_PRINT_NO_SUBSTMT);
        int len = ly_out_printed(out);
        printf("\r\nfind_schema_path:\r\n%s\r\n", printed);
    }
    ly_out_reset(out);

    // 创建树
    struct lyd_node *data = NULL;
    //lyd_new_path(NULL, ctx, "/acme-system:system/host-name", "huawei", 0, &data);
    lyd_new_path(NULL, ctx, "/acme-system:system/food/tea", "longjungcha", 0, &data);
    LY_ERR _r = lyd_print_mem(&str, data, LYD_JSON, LYS_PRINT_SHRINK);
    printf("\r\nLYD_JSON:\r\n%s\r\n", str);
    free(str);

    // 打印data path
    char *path_ =  lyd_path(data, LYD_PATH_STD, NULL, 0);
    printf("\r\nLYD_PATH_STD:\r\n%s\r\n", path_);
    free(path_);

    lyd_free_siblings(data);

    ASSERT_TRUE(1);
}
#endif